//
// Created by 罗外林 on 2024/1/3.
//

#include "EglThread.h"

#include "./Log.h"

#define LOG_TAG "EglThread"

EglThread::EglThread() {
    pthread_mutex_init(&_pthreadMutex, NULL);
    pthread_cond_init(&_pthreadCond, NULL);
}

EglThread::~EglThread() {
    pthread_mutex_destroy(&_pthreadMutex);
    pthread_cond_destroy(&_pthreadCond);
}

void *EglThread::eglThreadImpl(void *context) {
    EglThread *eglThread = static_cast<EglThread *>(context);
    if (!eglThread) {
        LOGD("eglThreadImpl error");
        return nullptr;
    }

    EglHelper *eglHelper = new EglHelper();
    if (eglHelper->initEgl(eglThread->_nativeWindow) != 0) {
        LOGE("initEgl error");
        return nullptr;
    }

    eglThread->_isExit = false;
    while (eglThread->_isExit == false) {
        switch (eglThread->_state) {
            case NO_SURFACE:
                eglThread->_onCreate();
                break;
            case FRESH_SURFACE:
                eglThread->_state = RENDERING;
                eglThread->_onChange(eglThread->_surfaceWidth, eglThread->_surfaceHeight);
                break;
            case RENDERING:
                eglThread->_onDraw();
                eglHelper->swapBuffers();

                if (eglThread->_renderType == RENDER_MODULE_AUTO) {
                    usleep(1000000 / 60);
                } else {
                    pthread_mutex_lock(&eglThread->_pthreadMutex);
                    pthread_cond_wait(&eglThread->_pthreadCond, &eglThread->_pthreadMutex);
                    pthread_mutex_unlock(&eglThread->_pthreadMutex);
                }
                break;
            case SURFACE_DESTROY:
                eglThread->_isExit = true;
                break;
            case STOP:
                if (eglThread->_renderType == RENDER_MODULE_AUTO) {
                    usleep(1000000 / 60);
                } else {
                    pthread_mutex_lock(&eglThread->_pthreadMutex);
                    pthread_cond_wait(&eglThread->_pthreadCond, &eglThread->_pthreadMutex);
                    pthread_mutex_unlock(&eglThread->_pthreadMutex);
                }
                break;
            default:
                break;
        }

        eglHelper->destroyEgl();
        delete eglHelper;
        eglHelper = nullptr;
        return nullptr;
    }
}

void EglThread::onSurfaceCreate(int windowType) {
    if (mEglThread == -1) {
        _state = NO_SURFACE;
        _nativeWindow = windowType;
        pthread_create(&mEglThread, NULL, EglThread::eglThreadImpl, this);
    }
}

void EglThread::onSurfaceChange(int width, int height) {
    if (mEglThread != -1) {
        _surfaceWidth = width;
        _surfaceHeight = height;
        _state = FRESH_SURFACE;
        notifyRender();
    }
}

void EglThread::setRenderModule(int renderModule) {
    _renderType = renderModule;
    notifyRender();
}

void EglThread::notifyRender() {
    pthread_mutex_lock(&_pthreadMutex);
    pthread_cond_signal(&_pthreadCond);
    pthread_mutex_unlock(&_pthreadMutex);
}

void EglThread::callbackOnChange(OnChange onChange) {
    _onChange = onChange;
}

void EglThread::callbackOnCreate(OnCreate oncreate) {
    _onCreate = oncreate;
}

void EglThread::callbackOnDraw(OnDraw onDraw) {
    _onDraw = onDraw;
}
